﻿using LightWadf.Core.Util;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace LightWadf.Core.Route
{
    /// <summary>
    /// 路由字典树
    /// 以路由 Item 作为节点值
    /// </summary>
    public class RouteTrie
    {
        public string ProcessorName { get; set; }
        public string MethodName { get; set; }
        /// <summary>
        /// 方法委托
        /// </summary>
        public Func<HttpContext, Dictionary<string, object>, object> Delegate { get; set; }

        /// <summary>
        /// RouteItem 是指路由的几个关键字中的一个
        /// </summary>
        private RouteItem item = null;
        /// <summary>
        /// 为了方便扩展而设置的字段
        /// 可设置该字段使得在解析路由的时候根据自定义规则来解析
        /// </summary>
        private Type itemType = null;
        /// <summary>
        /// 子树
        /// </summary>
        private List<RouteTrie> tries = null;

        public RouteTrie() 
        {
            this.itemType = typeof(RouteItem);
            this.tries = new List<RouteTrie>();
        }

        /// <summary>
        /// 如果扩展了 RouteItem，希望用扩展类进行解析，可以将其 Type 传入进行初始化
        /// </summary>
        /// <param name="itemType"></param>
        public RouteTrie(Type itemType)
        {
            if (!itemType.Equals(typeof(RouteItem)) &&typeof(RouteItem).IsAssignableFrom(itemType))
            {
                throw new TypeInitializationException("LightWadf.Core.Route.RouteTrie", new Exception("初始化参数 itemType 不是 RouteItem 类型或者不是 RouteItem 的子类型"));
            }
            this.itemType = itemType;
            this.tries = new List<RouteTrie>();
        }

        public RouteTrie(Queue<string> queue, string processorName, string methodName, Func<HttpContext, Dictionary<string, object>, object> dele)
        {
            if (queue == null || queue.Count == 0)
            {
                throw new TypeInitializationException("LightWadf.Core.Route.RouteTrie", new Exception("初始化参数 queue 为空集"));
            }
            else
            {
                this.itemType = typeof(RouteItem);
                if (queue.Count == 1)
                {
                    // 该 trie 为叶子节点
                    this.ProcessorName = processorName;
                    this.MethodName = methodName;
                    this.Delegate = dele;
                    this.item = Activator.CreateInstance(this.itemType) as RouteItem;
                    this.item.ParseItem(queue.Dequeue());
                }
                else
                {
                    this.item = Activator.CreateInstance(this.itemType) as RouteItem;
                    this.item.ParseItem(queue.Dequeue());
                    this.tries = new List<RouteTrie>();
                    this.tries.Add(new RouteTrie(queue, processorName, methodName, dele));
                }
            }
        }

        public void AddRoute(Queue<string> queue, string processorName, string methodName, Func<HttpContext, Dictionary<string, object>, object> dele)
        {
            if (queue == null || queue.Count == 0)
            {
                return;
            }
            else
            {
                string item = queue.Peek();
                if (this.tries == null) 
                {
                    this.tries = new List<RouteTrie>();
                }
                foreach (RouteTrie trie in this.tries)
                {
                    if (trie.item.Equal(item))
                    {
                        queue.Dequeue();
                        trie.AddRoute(queue, processorName, methodName, dele);
                        return;
                    }
                }
                this.tries.Add(new RouteTrie(queue, processorName, methodName, dele));
            }
        }

        public RouteTrie Search(Queue<string> queue, Dictionary<string, object> param)
        {
            if (queue == null || queue.Count == 0 || this.item != null && !this.item.Match(queue.Peek(), param))
            {
                return null;
            }
            else
            {
                Queue<string> q = new Queue<string>(queue);
                if (this.item != null)
                {
                    q.Dequeue();
                    // 边界条件
                    if (q.Count == 0 && !string.IsNullOrEmpty(this.ProcessorName) && !string.IsNullOrEmpty(this.MethodName))
                    {
                        return this;
                    }
                }
                if (this.tries == null) return null;
                foreach (RouteTrie trie in this.tries)
                {
                    RouteTrie result = trie.Search(q, param);
                    if (result != null) return result;
                }
            }
            return null;
        }

        public void MergeTrie(RouteTrie trie)
        {
            foreach (RouteTrie t in trie.tries)
            {
                bool isMerged = false;
                foreach (RouteTrie t2 in this.tries)
                {
                    if (t.item.Equal(t2.item))
                    {
                        if (t2.ProcessorName == null || t2.MethodName == null)
                        {
                            t2.ProcessorName = t.ProcessorName;
                            t2.MethodName = t.MethodName;
                            t2.Delegate = t.Delegate;
                        }
                        else if(t2.ProcessorName != t.ProcessorName || t2.ProcessorName != t.ProcessorName)
                        {
                        }
                        t2.MergeTrie(t);
                        isMerged = true;
                        continue;
                    }
                }
                if(!isMerged)
                    this.tries.Add(t);
            }
        }
    }
}